﻿//  --------------------------------
//  Copyright (c) AW Systems, Inc. All rights reserved.
//  This source code is made available under the terms of the Microsoft Public License (Ms-PL)
//  http://www.codeplex.com/SLAM/license
//  ---------------------------------

using System;
using System.Collections.Generic;
using System.Threading;
using System.Web;
using Microsoft.SharePoint;
using System.IO;

namespace AWS.SLAM.Configuration
{
	/// <summary>
	/// The SlamItemContext provides access to the SPListItem currently being processed by SLAM anywhere within SLAM's processing stack.
	/// </summary>
	public static class SlamItemContext
	{
		private static List<string> _contextFields = new List<string>();
		/// <summary>
		/// The SPListItem currently being processed by SLAM.
		/// </summary>
		public static SPListItem ListItem
		{
			get 
			{
				SPListItem currentListItem = null;
				object propertyValue = GetPropertyValue("CurrentSLAMListItem");
				if (propertyValue != null)
				{
					currentListItem = (SPListItem)propertyValue;
				}
				return currentListItem;
			}
			set
			{
				SetPropertyValue("CurrentSLAMListItem", value);
			}
		}
		
		/// <summary>
		/// Indiciates whether the SPListItem currently being processed by SLAM is configured
		/// to be slammed based on its Content Type or parent List.
		/// </summary>
		public static bool ProcessedByContentType 
		{
			get 
			{   
				bool currentListItemProcessedByContentType = false;
				object propertyValue = GetPropertyValue("CurrentSLAMListItemProcessedByContentType");
				if (propertyValue != null)
				{
					currentListItemProcessedByContentType = (bool)propertyValue;
				}
				return currentListItemProcessedByContentType;
			}
			set
			{
				SetPropertyValue("CurrentSLAMListItemProcessedByContentType", value);
			}
		}

		/// <summary>
		/// Indiciates whether the activity being logged for SLAM to perform using the SPListItem
		/// currentely processed should be committed.
		/// </summary>
		public static bool CommitActivity
		{
			get
			{
				bool currentListItemCommitActivity = true;
				object propertyValue = GetPropertyValue("CurrentSLAMListItemCommitActivity");
				if (propertyValue != null)
				{
					currentListItemCommitActivity = (bool)propertyValue;
				}
				return currentListItemCommitActivity;
			}
			set
			{
				SetPropertyValue("CurrentSLAMListItemCommitActivity", value);
			}
		}

		/// <summary>
		/// Log for use tracing activity at all levels of SLAM's processing.  Used primarily for logging SQL statements that may or may not
		/// called as determined by the CommitActivity flag.
		/// </summary>
		public static TextWriter ActivityLog
		{
			get
			{
				TextWriter currentActivityLog = null;
				object propertyValue = GetPropertyValue("CurrentSLAMListItemActivityLog");
				if (propertyValue != null)
				{
					currentActivityLog = (TextWriter)propertyValue;
				}
				return currentActivityLog;
			}
			set
			{
				SetPropertyValue("CurrentSLAMListItemActivityLog", value);
			}
		}

		/// <summary>
		/// Name of the List or Content Type configured to be managed by SLAM that corresponds with the SPListItem 
		/// currently being processed.  In the case of Lists this is the SPListItem's parent List Title, in the case
		/// of Content Types this is the SPListItem's Content Type Name or the Name of a parent Content Type.
		/// </summary>
		public static string TypeName
		{
			get
			{
				string currentTypeName = "";
				object propertyValue = GetPropertyValue("CurrentSLAMListItemTypeName");
				if (propertyValue != null)
				{
					currentTypeName = (string)propertyValue;
				}
				return currentTypeName;
			}
			set
			{
				SetPropertyValue("CurrentSLAMListItemTypeName", value);
			}
		}

		/// <summary>
		/// User LoginName of user that triggered the SLAM event.
		/// </summary>
		public static string UserLoginName
		{
			get
			{
				string currentUserLoginName = "";
				object propertyValue = GetPropertyValue("CurrentSLAMUserLoginName");
				if (propertyValue != null)
				{
					currentUserLoginName = (string)propertyValue;
				}
				return currentUserLoginName;
			}
			set
			{
				SetPropertyValue("CurrentSLAMUserLoginName", value);
			}
		}

		/// <summary>
		/// Resets the SLAM Item Context by clearing its properties
		/// </summary>
		public static void ResetContext()
		{
			foreach (string field in _contextFields)
			{
				//Check if HttpContext is available, if it is, clear the stored item from HttpContext Items
				if (HttpContext.Current != null)
				{
					if (HttpContext.Current.Items.Contains(field))
					{
						HttpContext.Current.Items.Remove(field);
					}
				}
				else
				{
					//If the HttpContext is not available, clear the stored item from the Thread's local data store
					Thread.FreeNamedDataSlot(field);
				}
			}
		}

		private static object GetPropertyValue(string propertyName)
		{
			object property = null;

			//Check if HttpContext is available, if it is, this property
			//should be stored in HttpContext Items
			if (HttpContext.Current != null)
			{
				if (HttpContext.Current.Items.Contains(propertyName))
				{
					property = HttpContext.Current.Items[propertyName];
				}
			}
			else
			{
				//If the HttpContext is not available, the context is needed within an 
				//asynchronous event in which case the context data should be stored
				//in the Thread's local data store
				LocalDataStoreSlot storeSlot = Thread.GetNamedDataSlot(propertyName);
				if (storeSlot != null)
				{
					property = Thread.GetData(storeSlot);
				}
			}
			return property;
		}

		private static void SetPropertyValue(string propertyName, object value)
		{
			//Check if HttpContext is available, if it is, store the property for this SLAM item context
			//in HttpContext Items
			if (HttpContext.Current != null)
			{
				if (!HttpContext.Current.Items.Contains(propertyName))
				{
					HttpContext.Current.Items.Add(propertyName, value);
				}
				else
				{
					HttpContext.Current.Items[propertyName] = value;
				}
			}
			else
			{
				//If the HttpContext is not available, the context is needed within an 
				//asynchronous event in which case the context data can be stored
				//in the Thread's local data store
				Thread.SetData(Thread.GetNamedDataSlot(propertyName), value);
			}

			if (!_contextFields.Contains(propertyName))
			{
				_contextFields.Add(propertyName);
			}
		}
	}
}
